using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Collections.Generic;

public partial class LookupDialog : System.Web.UI.Page
{
    private CrmHelper _crmHelper;
	private LookupClass _lkClass;
	private int _selectedIndex = -1;
	
    protected void Page_Load(object sender, EventArgs e)
    {
		if(!IsPostBack)
		{
			string className = Request.QueryString["class"];
			if(!string.IsNullOrEmpty(className))
			{
                LookupClassLoader lkLoader = new LookupClassLoader(this.CrmHelper);
				_lkClass = lkLoader.GetByName(className);
                foreach(LookupObject lkObject in _lkClass.Objects)
                {
					ListItem li = new ListItem();
                    li.Text = lkObject.DisplayName;
                    li.Value = lkObject.Name;
                    ddlObjectTypes.Items.Add(li);
                }
				this.ViewState["LookupClass"] = _lkClass;
				
				if(ddlObjectTypes.Items.Count == 1)
				{
					ddlObjectTypes.Enabled = false;
				}
			}
			
			string allowMultiselect = Request.QueryString["multiselect"];
			if(string.IsNullOrEmpty(allowMultiselect))
			{
				allowMultiselect = "0";
			}			
			if(allowMultiselect.ToLower().Equals("true") || allowMultiselect.Equals("1"))
			{
				this.crmGrid.AllowMultiSelect = true;
			}
			else
			{
				this.crmGrid.AllowMultiSelect = false;
			}

			string enableRemove = Request.QueryString["enableremove"];
			if (string.IsNullOrEmpty(enableRemove))
			{
				enableRemove = "0";
			}
			if (enableRemove.ToLower().Equals("true") || enableRemove.Equals("1"))
			{
				this.btnRemoveValue.Attributes.Remove("disabled");
			}
			else
			{
				this.btnRemoveValue.Attributes.Add("disabled", "disabled");
			}
		}
		else
		{
			_lkClass = this.ViewState["LookupClass"] as LookupClass;
			_selectedIndex = (int)this.ViewState["SelectedIndex"];
		}

		BindLookupObject();
    }

	protected void ddlObjectTypes_SelectedIndexChanged(object sender, EventArgs e)
	{
		//BindLookupObject();
	}

	private void BindLookupObject()
	{
		if (_lkClass != null && ddlObjectTypes.SelectedIndex >= 0)
		{
			if(_selectedIndex != ddlObjectTypes.SelectedIndex)
			{
				this.crmGrid.Clear();
				_selectedIndex = ddlObjectTypes.SelectedIndex;
				ViewState["SelectedIndex"] = _selectedIndex;
			}

			BoundColumn imageCol = new BoundColumn();
			imageCol.HeaderText = string.Empty;
			imageCol.DataField = string.Empty;
			imageCol.SortExpression = "!";
			imageCol.HeaderStyle.Width = new Unit(32, UnitType.Pixel);
			imageCol.ItemStyle.Width = new Unit(32, UnitType.Pixel);
			this.crmGrid.Columns.Add(imageCol);

			LookupObject lkObject = _lkClass.Objects[ddlObjectTypes.SelectedIndex];
			foreach(KeyValuePair<string, string> column in lkObject.Columns)
			{
				BoundColumn gridCol = new BoundColumn();
				gridCol.HeaderText = column.Value;
				gridCol.DataField = column.Key;
				gridCol.SortExpression = column.Key;
				this.crmGrid.Columns.Add(gridCol);
			}
			this.crmGrid.Rebind();
		}
	}

    public CrmHelper CrmHelper
    {
        get
        {
            if (_crmHelper == null)
            {
                _crmHelper = new CrmHelper(Request.QueryString["orgname"]);
            }
            return _crmHelper;
        }
    }
    
    public LookupObject SelectedObject
    {
		get
		{
			return _lkClass.Objects[ddlObjectTypes.SelectedIndex];
		}
    }

	protected void crmGrid_ItemDataBound(object sender, DataGridItemEventArgs e)
	{
		if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.SelectedItem)
		{
			//HtmlImage imageIcon = e.Item.FindControl("imageIcon") as HtmlImage;
			//if(imageIcon != null)
			//{
			//    imageIcon.Src = this.ResolveClientUrl(this.SelectedObject.Icon);
			//}

			e.Item.Cells[1].Text = "<img alt=\"\" src=\"" + this.ResolveClientUrl(this.SelectedObject.Icon) + "\"/>";
		}
	}
    
    protected void crmGrid_QueryDataSource(object sender, QueryDataSourceEventArgs args)
    {
		if (_lkClass == null || ddlObjectTypes.SelectedIndex < 0)
		{
			return;
		}
    
		LookupObject lkObject = _lkClass.Objects[ddlObjectTypes.SelectedIndex];
		
		MetadataSdk.EntityMetadata entityMetadata = CrmHelper.GetEntityMetadata(lkObject.Name);
		crmGrid.DataIdField = entityMetadata.PrimaryKey;
		crmGrid.DataLabelField = entityMetadata.PrimaryField;
		crmGrid.DataCodeField = "obj-typecode";
		
		DataTable dataSource = PrepareDataSource(lkObject, args);
		
		this.crmGrid.DataSource = dataSource;
		this.crmGrid.DataBind();
    }
	
	private DataTable PrepareDataSource(LookupObject lkObject, QueryDataSourceEventArgs args)
	{
		MetadataSdk.EntityMetadata entityMetadata = CrmHelper.GetEntityMetadata(lkObject.Name);
        Dictionary<string, MetadataSdk.AttributeMetadata> entityAttributes = new Dictionary<string, MetadataSdk.AttributeMetadata>();
        foreach (MetadataSdk.AttributeMetadata attribute in entityMetadata.Attributes)
        {
            entityAttributes[attribute.LogicalName] = attribute;
        }
		
		bool primaryKeyPresent = false;
		bool primaryFieldPresent = false;
		
		DataTable dataTable = new DataTable();
		foreach (KeyValuePair<string, string> column in lkObject.Columns)
		{
			dataTable.Columns.Add(new DataColumn(column.Key));
			if(!primaryKeyPresent && (column.Key == entityMetadata.PrimaryKey))
			{
				primaryKeyPresent = true;
			}
			if(!primaryFieldPresent && (column.Key == entityMetadata.PrimaryField))
			{
				primaryFieldPresent = true;
			}
		}
		
		XmlDocument xdQuery = new XmlDocument();
		xdQuery.LoadXml(lkObject.Query);
		XmlElement fetchXmlNode = xdQuery.DocumentElement;
        XmlNode entityNode = fetchXmlNode.SelectSingleNode("entity");
            
		if(!primaryKeyPresent)
		{
			dataTable.Columns.Add(new DataColumn(entityMetadata.PrimaryKey));
			XmlElement primaryAttrNode = entityNode.SelectSingleNode("attribute[@name=" + "'" + entityMetadata.PrimaryKey + "'" + "]") as XmlElement;
            if (primaryAttrNode == null)
            {
                primaryAttrNode = xdQuery.CreateElement("attribute");
                primaryAttrNode.SetAttribute("name", entityMetadata.PrimaryKey);
            }
			entityNode.AppendChild(primaryAttrNode);
		}

		if (!primaryFieldPresent)
		{
			dataTable.Columns.Add(new DataColumn(entityMetadata.PrimaryField));
			XmlElement primaryAttrNode = entityNode.SelectSingleNode("attribute[@name=" + "'" + entityMetadata.PrimaryField + "'" + "]") as XmlElement;
            if (primaryAttrNode == null)
            {
                primaryAttrNode = xdQuery.CreateElement("attribute");
                primaryAttrNode.SetAttribute("name", entityMetadata.PrimaryField);
            }
			entityNode.AppendChild(primaryAttrNode);
		}
		
		dataTable.Columns.Add(new DataColumn("obj-typecode"));
		
		if (string.IsNullOrEmpty(args.SortExpression))
		{
			args.SortExpression = lkObject.OrderByColumn;
			if(lkObject.DescendingOrder)
			{
				args.SortDirection = SortDirection.Descending;
			}
			else
			{
				args.SortDirection = SortDirection.Ascending;
			}
		}
		
		if(args.SortExpression != lkObject.OrderByColumn)
		{
			XmlNode orderNode = entityNode.SelectSingleNode("order");
			if(orderNode == null)
			{
				orderNode = xdQuery.CreateElement("order");
				entityNode.AppendChild(orderNode);
			}
			XmlAttribute orderAttr = orderNode.Attributes["attribute"];
			if(orderAttr == null)
			{
				orderAttr = xdQuery.CreateAttribute("attribute");
				orderNode.Attributes.Append(orderAttr);
			}
			orderAttr.Value = args.SortExpression;
			lkObject.OrderByColumn = args.SortExpression;
		}
		
		fetchXmlNode.SetAttribute("count", "50");
		fetchXmlNode.SetAttribute("page", args.PageNumber.ToString());
		fetchXmlNode.SetAttribute("paging-cookie", args.PagingCookie);
		
		if((args.SortDirection == SortDirection.Descending && !lkObject.DescendingOrder) || (args.SortDirection == SortDirection.Ascending && lkObject.DescendingOrder))
		{
			lkObject.DescendingOrder = !lkObject.DescendingOrder;
			XmlNode orderNode = fetchXmlNode.SelectSingleNode("entity/order");
			if (orderNode != null)
			{
				XmlAttribute orderDescAttr = orderNode.Attributes["descending"];
				if (orderDescAttr == null)
				{
					orderDescAttr = xdQuery.CreateAttribute("descending");
					orderNode.Attributes.Append(orderDescAttr);
				}
				orderDescAttr.Value = lkObject.DescendingOrder.ToString().ToLower();
			}
		}
        
        XmlElement filterNode = entityNode.SelectSingleNode("filter[@isquickfindfields='1']") as XmlElement;
        string searchValue = txtSearch.Text.Trim();
        if (searchValue != string.Empty)
        {
            string searchPattern = searchValue.Replace("%","[%]").Replace('*', '%');
            if (!searchPattern.EndsWith("%"))
            {
                searchPattern += "%";
            }
            if (filterNode == null)
            {
                filterNode = xdQuery.CreateElement("filter");
                filterNode.SetAttribute("isquickfindfields", "1");
                entityNode.AppendChild(filterNode);
            }
            filterNode.SetAttribute("type", "or");
            foreach (KeyValuePair<string, string> column in lkObject.Columns)
            {
                string attributeName = column.Key;
                if (attributeName == entityMetadata.PrimaryKey)
                {
                    continue;
                }
                MetadataSdk.AttributeMetadata attrMetadata = null;
                if (entityAttributes.TryGetValue(attributeName, out attrMetadata) == false)
                {
                    continue;
                }
                XmlElement conditionNode = filterNode.SelectSingleNode("condition[@attribute='" + attributeName + "']") as XmlElement;
                string op = "like";
                string searchText = searchPattern;
                switch (attrMetadata.AttributeType.Value)
                {
                    case MetadataSdk.AttributeType.Lookup:
                    case MetadataSdk.AttributeType.Owner:
                    case MetadataSdk.AttributeType.Customer:
                    case MetadataSdk.AttributeType.Picklist:
                    case MetadataSdk.AttributeType.Boolean:
                    case MetadataSdk.AttributeType.State:
                    case MetadataSdk.AttributeType.Status:
                    {
                        attributeName = attributeName + "name";
                        break;
                    }
                    case MetadataSdk.AttributeType.DateTime:
                    {
                        DateTime dateTime;
                        if (DateTime.TryParse(searchValue, out dateTime) == false)
                        {
                            if (conditionNode != null)
                            {
                                filterNode.RemoveChild(conditionNode);
                            }
                            continue;
                        }
                        op = "on";
                        searchText = string.Format("{0:yyyy'-'MM'-'dd'T'HH':'mm':'ss }", dateTime);
                        break;
                    }
                    case MetadataSdk.AttributeType.PartyList:
                    {
                        //Conditions not supported for PartyList attributes
                        continue;
                    }
                    case MetadataSdk.AttributeType.Money:
                    {
                        decimal value;
                        if (Decimal.TryParse(searchValue, out value) == false)
                        {
                            if (conditionNode != null)
                            {
                                filterNode.RemoveChild(conditionNode);
                            }
                            continue;
                        }
                        op = "eq";
                        searchText = value.ToString();
                        break;
                    }
                    case MetadataSdk.AttributeType.Decimal:
                    {
                        decimal value;
                        if (Decimal.TryParse(searchValue, out value) == false)
                        {
                            if (conditionNode != null)
                            {
                                filterNode.RemoveChild(conditionNode);
                            }
                            continue;
                        }
                        op = "eq";
                        searchText = value.ToString();
                        break;
                    }
                    case MetadataSdk.AttributeType.Integer:
                    {
                        int value;
                        if (int.TryParse(searchValue, out value) == false)
                        {
                            if (conditionNode != null)
                            {
                                filterNode.RemoveChild(conditionNode);
                            }
                            continue;
                        }
                        op = "eq";
                        searchText = value.ToString();
                        break;
                    }
                    case MetadataSdk.AttributeType.Float:
                    {
                        float value;
                        if (float.TryParse(searchValue, out value) == false)
                        {
                            if (conditionNode != null)
                            {
                                filterNode.RemoveChild(conditionNode);
                            }
                            continue;
                        }
                        op = "eq";
                        searchText = value.ToString();
                        break;
                    }
                }
                if (conditionNode == null)
                {
                    conditionNode = xdQuery.CreateElement("condition");
                    filterNode.AppendChild(conditionNode);
                    conditionNode.SetAttribute("attribute", attributeName);
                }
                conditionNode.SetAttribute("operator", op);
                conditionNode.SetAttribute("value", searchText);
            }
        }
        else if(filterNode != null)
        {
            entityNode.RemoveChild(filterNode);
        }

        XmlNodeList conditionNodes = fetchXmlNode.GetElementsByTagName("condition");
        foreach (XmlElement conditionNode in conditionNodes)
        {
            XmlAttribute fromParamAttr = conditionNode.Attributes["fromparam"];
            if (fromParamAttr == null)
            {
                continue;
            }
            string paramValue = this.Request.QueryString[fromParamAttr.Value];
            if (paramValue == null)
            {
                //throw
                paramValue = string.Empty;
            }
            conditionNode.SetAttribute("value", paramValue);
            conditionNode.Attributes.Remove(fromParamAttr);
        }

		string fetchXml = fetchXmlNode.OuterXml;
		lkObject.Query = fetchXml;

		CrmSdk.CrmService crmService = CrmHelper.GetCrmService();
		string resultXml = crmService.Fetch(fetchXml);
		
		XmlDocument xdResults = new XmlDocument();
		xdResults.LoadXml(resultXml);
		XmlNode resultSetNode = xdResults.DocumentElement;
		XmlNodeList resultNodes = resultSetNode.SelectNodes("result");
		foreach(XmlNode resultNode in resultNodes)
		{
			DataRow row = dataTable.NewRow();
			foreach (XmlNode childNode in resultNode.ChildNodes)
			{
				XmlElement childElement = childNode as XmlElement;
				if(childElement == null)
				{
					continue;
				}
				int iIndex = dataTable.Columns.IndexOf(childElement.Name);
				if(iIndex >= 0)
				{
					MetadataSdk.AttributeMetadata attrMetadata = null;
                    if(entityAttributes.TryGetValue(childElement.Name, out attrMetadata) == false)
                    {
                        continue;
					}
					switch(attrMetadata.AttributeType.Value)
					{
						case MetadataSdk.AttributeType.Lookup:
						case MetadataSdk.AttributeType.Owner:
						case MetadataSdk.AttributeType.Customer:
						{
							row[iIndex] = childElement.GetAttribute("name");
							//TODO: Link
							break;
						}
						case MetadataSdk.AttributeType.Picklist:
                        case MetadataSdk.AttributeType.Boolean:
                        case MetadataSdk.AttributeType.State:
                        case MetadataSdk.AttributeType.Status:
						{
						    row[iIndex] = childElement.GetAttribute("name");
							break;
						}
                        case MetadataSdk.AttributeType.DateTime:
                        {
                            string date = childElement.GetAttribute("date");
                            string time = childElement.GetAttribute("time");
                            string datetime = string.Empty;
                            if (!string.IsNullOrEmpty(date))
                            {
                                datetime += date;
                            }
                            if (!string.IsNullOrEmpty(time))
                            {
                                if (datetime != string.Empty)
                                {
                                    datetime += " ";
                                }
                                datetime += time;
                            }
                            if (datetime == string.Empty)
                            {
                                datetime = childElement.InnerText;
                            }
                            row[iIndex] = datetime;
                            break;
                        }
                        //case MetadataSdk.AttributeType.PartyList:
                        //{
                        //    continue;
                        //}
                        case MetadataSdk.AttributeType.Integer:
                        case MetadataSdk.AttributeType.Float:
                        case MetadataSdk.AttributeType.Money:
                        case MetadataSdk.AttributeType.Decimal:
                        {
                            row[iIndex] = childElement.GetAttribute("formattedvalue");
                            break;
                        }
						default:
						{
							row[iIndex] = childElement.InnerText;							
							break;
						}
					}
				}
			}
			row[dataTable.Columns.Count - 1] = lkObject.TypeCode;
			dataTable.Rows.Add(row);
		}
		
		XmlAttribute moreRecordsAttr = resultSetNode.Attributes["morerecords"];
		if(moreRecordsAttr != null)
		{
			string morerecords = moreRecordsAttr.Value;
			if(morerecords == "1" || morerecords == "true")
			{
				args.HasMorePages = true;
			}
			else
			{
				args.HasMorePages = false;
			}
		}
		
		XmlAttribute pagingCookieAttr = resultSetNode.Attributes["paging-cookie"];
		if (pagingCookieAttr != null)
		{
			args.PagingCookie = pagingCookieAttr.Value;
		}
		
		return dataTable;
	}   
    
}
